import { GameNode, StepNode, BodyNode, ButtonNode, Vector2, RegisterGameNode, Alias } from './gameClass';
import { IapNode, parse } from '../parse';
import { getFieldAnnotation } from './annotation';
import { UVariable } from './UVariable';
import { isValid } from '../Utils';
import { IGame } from '../Common';

export var config = {
    zIndex: {
        bg: 1,
        effect: 7,
        galText: 6,
        btn: 3,
        option: 4,
        hoverText: 5,
    },
};

//#region 绘图

function createPlayButton(): HTMLElement {
    var button = document.createElement('div');
    button.style.position = 'absolute';
    button.style.left = '0%';
    button.style.right = '0%';
    button.style.bottom = '20%';
    button.style.textAlign = 'center';
    button.style.background = 'linear-gradient(45deg,transparent, white, transparent)';
    button.textContent = '点击我进行游玩';
    button.style.zIndex = '' + config.zIndex.btn;
    return button;
}

function createAudio() {
    var audio: HTMLAudioElement = document.createElement('audio');
    audio.style.display = 'none';
    return audio;
}

function createVideo(): HTMLVideoElement {
    var video: HTMLVideoElement = document.createElement('video');
    video.style.display = 'none';
    video.style.zIndex = '1';
    return video;
}

function createGalText(): HTMLElement {
    var button = document.createElement('div');
    button.style.position = 'absolute';
    button.style.left = '0%';
    button.style.right = '0%';
    button.style.bottom = '0%';
    button.style.textAlign = 'center';
    button.style.background = 'linear-gradient(45deg,transparent, white, transparent)';
    button.textContent = '点击我进行游玩';
    button.style.zIndex = '' + config.zIndex.btn;
    button.style.padding = '5px';
    // button.style.textShadow = "2px 0px 10px black";
    return button;
}

var id = 0;
function nextID(): string {
    return "iapGID-"+ id++;
}
    

export default class Game implements IGame {
    static current?: Game = undefined;
    /** 原解析后对象 */
    iapNode!: IapNode;
    iapNodeIdMap:  { [x: string]: IapNode } =  {};

    /**游戏节点 */
    bodyNode!: BodyNode;
    /**自定义变量 */
    customVariables: {[x: string]: any} = {};
    /** 主要Dom对象,这里是iframe */
    el!: HTMLIFrameElement;
    /** 存放其他dom的dom */
    body!: HTMLDivElement;
    /**背景 */
    bgEl!: HTMLImageElement;
    bgmAudio!: HTMLAudioElement;
    seAudio!: HTMLAudioElement;
    errorEl!: HTMLElement;

    interaction: boolean = false; //是否可交互

    buCtr: boolean = false;

    clickImageDuration: number = -1;

    playButton!: HTMLElement;

    videoEl!: HTMLVideoElement;
    galEL!: HTMLElement;

    // sceneId?: string = undefined;
    currentStepId!: string;

    hoverTextEl!: HTMLElement;

    /**id映射表 */
    idMap: { [x: string]: GameNode } = {};

    // notDestroyRecord: string[] = [];

    //场景中的对象
    gameObjectIds: string[] = [];

    //选择项
    optionGroup!: HTMLElement;

    size: Vector2 = new Vector2(0,0);

    /**设置的字体大小 */
    fontSize: number = 16;
    /** 基础大小 */
    baseFontSize: number = 16;
    /** 基础url */
    baseUrl!: string;

    gamefps = 30;

    init (iapNode: IapNode) {
        this.iapNode = iapNode;
        this.el = document.createElement("iframe");
        this.el.style.minWidth = '200px';
        this.el.style.minHeight = '200px';
        this.el.style.width = "100%";
        this.el.style.height = "100%";
        this.el.style.border = "none";
        this.el.classList.add("iap-iframe");
    }

    start() {
        //TODO 创建打印错误信息节点

        //加载样式
        var style = document.createElement("style");
        style.appendChild(document.createTextNode(require("./mycss.css")));
        this.el.contentDocument?.head.appendChild(style);
  

        this.body = document.createElement("div");
        this.body.classList.add("iap-body");
        this.el.contentDocument?.body.appendChild(this.body);
        
       try{
            this.start2();
       }
       catch(e) {
            if(e instanceof Error) {
                this.printError(e.message);
            }
            else if(typeof e == "string"){
                this.printError(e);
            }
       }
       
    }
    
    start2() {
        //初始化
        var game = this;
        var i;
         //#region IapNode转换为 GameNode
         if(this.iapNode.tag != BodyNode.tag) {
            throw new Error(`根节点不是${BodyNode.tag}`);
        }

        //获取根节点信息
        this.fontSize = this.iapNode.numberAttrOrDefault("font-size", 16)
        if(!this.iapNode.hasAttr("size") || !this.iapNode.getAttr("size")) {
            throw new Error(`IAP节点size属性是必选的,例: size=1024,576`);
        }
        try{
            this.size = Vector2.parse(this.iapNode.getAttr("size")!);
        }
        catch(_) {
            throw new Error(`IAP节点size值不规范,请检查,例: size=1024,576`);
        }


        //设置IapNode的idMAP
        this.iapNode.depthForEach(function(node) {
            if (!node.getAttr("i")) {
                node.setAttr("i", nextID()); 
            }
            game.iapNodeIdMap[node.getAttr("i")!] = node;
        })

        //cp功能
        this.iapNode.depthForEach((node) => {
            if (node.getAttr("cp")) {
                var cpTarget = this.iapNodeIdMap[node.getAttr("cp")!]
                if (cpTarget) {
                    for (let cpAttrKey in cpTarget.attrs) {
                        if (cpAttrKey != "i" && !node.getAttr(cpAttrKey)) {
                            node.setAttr(cpAttrKey, cpTarget.getAttr(cpAttrKey)!);
                        }
                    }
                }
            }
        })
        console.log("cp后", this.iapNode);

        //获取自定义变量 s-开头是string n-开始是number
        for (var key in this.iapNode.attrs) {
            let value :any = this.iapNode.getAttr(key);
            if(key.startsWith("s-")) {
                this.customVariables[key.substring(2)] = this.iapNode.getAttr(key);
            }
            else if(key.startsWith("n-")) {
                if(value === '') {
                    value = 0;
                }
                else {
                    try {
                        value = parseFloat(value)
                    } catch(_) {
                        return this.printError(`自定义变量${key}无法解析`);
                    }
                }
                this.customVariables[key.substring(2)] = value;
            }
            else if(key.startsWith("b-")) {
                if(value == "false") {
                    this.customVariables[key.substring(2)] = false;
                }else {
                    this.customVariables[key.substring(2)] = true;
                }
            }
        }
        //设置字体
        this.resize();
        //开始转换
        this.bodyNode = <BodyNode>this.IapNodeToGameNode(this.iapNode);
        //#endregion IapNode转换为 GameNode

        
        var contentWindow = this.el.contentWindow!;
        //先赋值idMap和game
        this.bodyNode.depthChildForEach(function (iap) {
            var id = iap.id;
            if (game.idMap[id]) {
                throw new Error(`存在多个相同id为${id}节点`);
            }
            game.idMap[id] = iap;
            iap.game = game;
        });

        var steps = this.bodyNode.findByTag<StepNode>(StepNode.tag);
        //自动赋值下一个步骤
        if (!this.bodyNode.nextStepID.srcValue && steps.length > 0) {
            this.bodyNode.nextStepID.srcValue = steps[0].id;
        }
        for (i = 0; i < steps.length; i++) {
            var step = steps[i];
            if (step.nextStepID.srcValue != 'no' && step.nextStepID.srcValue == null) {
                if (i == steps.length - 1) {
                    step.nextStepID.srcValue = steps[0].id;
                    step.nextStepID.dataConvert();
                }
                else {
                    step.nextStepID.srcValue = steps[i+1].id;
                    step.nextStepID.dataConvert();
                }
            }
        }

        //创建对象
     
        this.bgEl = document.createElement('img');
        this.bgEl.classList.add("iap-body-bg");
        this.bgEl.src = this.bodyNode.cover.calcValue();
        this.bgEl.style.zIndex = '' + config.zIndex.bg;

        this.hoverTextEl = document.createElement("div");
        this.hoverTextEl.classList.add("iap-hover-text")
        this.hoverTextEl.style.display = "none";
        this.hoverTextEl.style.zIndex = config.zIndex.hoverText + "";
        this.hoverTextEl.style.fontSize = this.defaultFontSize();

        this.playButton = createPlayButton();
        this.body.appendChild(this.bgEl);
        this.body.appendChild(this.playButton);
        this.body.appendChild(this.hoverTextEl);

        this.body.addEventListener('click', this.onBodyClick.bind(this));

        this.optionGroup = document.createElement('div');
        this.optionGroup.style.position = 'absolute';
        this.optionGroup.style.zIndex = "" + config.zIndex.option;
        this.optionGroup.style.left = '50%';
        this.optionGroup.style.top = '10%';
        this.optionGroup.style.transform = 'translateX(-50%)';
        this.optionGroup.style.minWidth = '50%';
        this.optionGroup.style.fontSize = this.defaultFontSize();
        this.body.appendChild(this.optionGroup); 

        //窗口离开事件
        document.addEventListener("visibilitychange", function() {
            if(game) {
                if (document.visibilityState == "hidden") {
                    game?.bgmAudio?.pause();
                }else if(document.visibilityState == "visible") {
                    game?.bgmAudio?.play();
                }
            }
        })

        contentWindow.addEventListener("resize", this.resize.bind(this));


        setInterval(()=> {
            this.bodyNode.update();
        }, 1000 / this.gamefps)
    }

    

    IapNodeToGameNode(node: IapNode): GameNode | undefined {
        var iap = this.IapNodeToGameNodeNoChildren(node);
        if(iap) {
            for (let child of node.children) {
                var iap2 = this.IapNodeToGameNode(child)
                if (iap2) {
                    iap.children.push(iap2);
                }
            }
        }
        return iap;
    }
    
    IapNodeToGameNodeNoChildren(node: IapNode) : GameNode | undefined {
        var tag = node.tag;
        var gameNodeCtr = RegisterGameNode.nameMap[tag];
        if (gameNodeCtr) {
            var gameNode = new gameNodeCtr();
            gameNode.id = node.getAttr("i")!;
            for (var key in gameNode) {
                if(Object.prototype.hasOwnProperty.call(gameNode, key)) {
                    //@ts-ignore
                    var value = <any>gameNode[key]
                    var alias = getFieldAnnotation(gameNodeCtr.prototype, key, Alias);
                    if(alias != undefined) {
                        var aliasNames = alias.value;
                        if(value instanceof UVariable) {
                            value.game = this;
                            var srcValue = node.getAttr(...aliasNames);
                            if(isValid(srcValue)) {
                                value.srcValue = srcValue!;
                            }
                            value.init();
                        }
                    }
                }
            }
            return gameNode;
        }
        return undefined;
    }

    resize() {
        var contentWindow = this.el.contentWindow!;
        var contentDocument = this.el.contentDocument!;
        var contentHtml = contentDocument.getElementsByTagName("html")[0]!;
        this.el.style.height = this.size.y / this.size.x * contentWindow.innerWidth + "px";
        contentHtml.style.fontSize = ( contentWindow.innerWidth / this.size.x * this.baseFontSize).toFixed(3) + "px";
    }

    onBodyClick(e: Event) {
        if (!this.interaction) {
            this.interaction = true;
            this.playButton.style.display = 'none';

            this.bodyNode.children.forEach((c) => c.create);

            var nextID = this.bodyNode.nextStepID.calcValue();
            if (nextID) {
                this.nextSceneById(nextID);
            }
        } else {
            this.nextScene();
        }
        e.stopPropagation();
        return false;
    }

    showBG(url: string) {
        if (this.bgEl) {
            this.bgEl.src = url;
            this.bgEl.style.display = '';
        }
    }
    hideBG() {
        if (this.bgEl) {
            this.bgEl.style.display = 'none';
        }
    }

    playSe(url: string, loop = false) {
        if (this.seAudio == null) {
            this.seAudio = createAudio();
            this.body.appendChild(this.seAudio);
        }
        if (url == null) {
            this.stopSe();
        } else {
            this.seAudio.src = url;
            this.seAudio.loop = loop;
            this.seAudio.play();
        }
    }

    playBGM(url: string, loop = true) {
        if (this.bgmAudio == null) {
            this.bgmAudio = createAudio();
            this.body.appendChild(this.bgmAudio);
        }
        if (url) {
            //@ts-ignore
            if (this.bgmAudio.iapUrp != url) {
                //@ts-ignore
                this.bgmAudio.iapUrp = url;
                this.bgmAudio.src = url;
                this.bgmAudio.play();
                this.bgmAudio.loop = loop;
            }
        }
    }

    stopSe() {
        if (this.seAudio) {
            this.seAudio.pause();
            this.seAudio.currentTime = 0;
        }
    }

    playVideo(url: string) {
        if (!this.buCtr) return;

        if (!this.videoEl) {
            this.videoEl = createVideo();
            this.videoEl.style.width = '100%';
            this.body.appendChild(this.videoEl);
        }
        this.bgEl.style.display = 'none';
        this.videoEl.style.display = '';
        this.videoEl.src = url;
        this.videoEl.play();
        this.videoEl.addEventListener('pause', function () {
            // console.log("视频播放结束");
            //恢复
        });
    }

    stopAndHideVideo() {
        if (this.videoEl) {
            this.videoEl.pause();
            this.videoEl.style.display = 'none';
        }
    }

    showGalText(text: string) {
        if (!this.galEL) {
            this.galEL = createGalText();
            this.galEL.style.fontSize = this.defaultFontSize();
            this.galEL.style.zIndex = '' + config.zIndex.galText;
            this.body.appendChild(this.galEL);
        }
        this.galEL.style.display = '';
        this.galEL.textContent = text;
    }
    hideGalText() {
        if (this.galEL) {
            this.galEL.style.display = 'none';
        }
    }

    timeoutId: any;
    safeDurationRecord : number[] = [];

    nextScene(isAuto = false) {
        var currentStep = <StepNode>this.idMap[this.currentStepId];
        if (!currentStep) return;

        var nextStepId = currentStep.nextStepID.calcValue();
        console.log("currentStep", currentStep, "nextStepId", nextStepId)
        if (nextStepId != 'no' && nextStepId != null ) {
            this.nextSceneById(nextStepId, isAuto);
        }
    }

    nextSceneById(id: string, isAuto = false) {
        //进入下一个step前的操作
        var currentStep = <StepNode>this.idMap[this.currentStepId];
        var nextStep = <StepNode>this.idMap[id];
        console.log("currentStep", currentStep, "nextStep", nextStep)
        if(currentStep) {
            //销毁和离开销毁
            currentStep.destroy();
            this.forcedDestroy(currentStep.leaveDestroy.calcValue());    
        }
        if(nextStep == null) {
            return;
        }

        //进入销毁
        this.forcedDestroy(nextStep.enterDestroy.calcValue());
        this.currentStepId = id;
        if (nextStep == null) return;
        this.hoverTextEl.style.display = "none";
        nextStep.create();
        if(nextStep.duration.srcValueIsValid() &&  nextStep.duration.calcValue() >= 0) {
            if(this.timeoutId) {
                clearTimeout(this.timeoutId);
                this.timeoutId = undefined;
            }
            //安全检测
            var flag = true;
            if(isAuto) {
                this.safeDurationRecord.push(Date.now());
                if(this.safeDurationRecord.length > 5) {
                    var inst = this.safeDurationRecord[this.safeDurationRecord.length - 1] - this.safeDurationRecord[0];
                    if (inst < 1000) {
                        flag = false;
                        this.printError("自动一下个step，发现短时间多次触发，这是违规行为, 已取消本次自动下一个场景");
                        // this.stopGame();
                    } else {
                        this.safeDurationRecord.shift();
                    }
                }
            }
            if(flag)
            {
                this.timeoutId = setTimeout(()=> {
                    this.nextScene(true);
                }, nextStep.duration.value * 1000);
            }
        }
    }

    printError(error: string) {
        if(!this.errorEl) {
            this.errorEl = document.createElement("div");
            this.errorEl.classList.add("iap-error");
            this.errorEl.style.fontSize = this.baseFontSize + "px";
            this.body.appendChild(this.errorEl)
        }
        this.errorEl.style.display = "";
        this.errorEl.textContent = error;
        console.error(error);
    }

    stopGame() {
    }


    forcedDestroy(ids: string[] | undefined) {
        if (ids && ids.length > 0) {
            for (let id of ids) {
                this.idMap[id].forcedDestruction();
            }
        }
    }

    playEffects(names: string[] | undefined) {
        if (!names) return;
        for (let name of names) {
            this.playEffect(name);
        }
    }

    /**屏幕闪特性 */
    playEffect(name: string) {
        switch (name) {
            case 'glint':
                {
                    var div = document.createElement('div');
                    div.style.zIndex = '' + config.zIndex.effect;
                    this.body.appendChild(div);
                    div.classList.add('iap-effect-glint');
                    setTimeout(() => div.remove(), 1 * 1000);
                }
                break;
            case 'shake':
                {
                    this.bgEl.classList.add('iap-effect-shake');
                    setTimeout(() => this.bgEl.classList.remove('iap-effect-shake'), 300);
                }
                break;
        }
    }

    calcLength(size: number | undefined) : string {
        if(size !== 0 && !!size && !this.fontSize) {
            return "1rem";
        }
        return (size! / this.baseFontSize ).toFixed(3) + "rem" ;
    }

    defaultFontSize() {
        return this.calcLength(this.fontSize);
    }

}
